﻿using System;
using Graphing.ViewModel;
using Graphing.Model;
using Graphing;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.ComponentModel;
using Graphing.Services;

namespace Graphing.ViewModel
{
    #region Enums

    // Enum to help determin the Graphing Type (2D or 3D).
    public enum GraphType
    {
        Two_D = 0, Three_D
    }

    #endregion

    public class PointsViewModel : ViewModelBase, IDataErrorInfo
    {
        #region Fields

        private String _x;
        private String _y;
        private String _z;
        private ObservableCollection<Point> _pointsList = GenericSingleton<ObservableCollection<Point>>.GetInstance();
        private ICommand _addPointCommand;
        private ICommand _editPointCommand;
        private ICommand _graphCommand;
        private GraphType _type = new GraphType();
        public Scale graphScale = GenericSingleton<Scale>.GetInstance();
        private IWindowOpenService _openEditWindow = GenericSingleton<IWindowOpenService>.GetInstance();
        private DrawPointService test = GenericSingleton<DrawPointService>.GetInstance();

        #endregion // Fields.

        #region Constructor

        public PointsViewModel()
        {
            PointsList = new ObservableCollection<Point>();
            _x = "0";
            base.OnPropertyChanged("_x");
            _y = "0";
            base.OnPropertyChanged("_y");
            _z = "0";
            base.OnPropertyChanged("_z");
            isValid = true;

            base.OnPropertyChanged("isValid");
        }

        #endregion // Fields.

        #region Properties

        // Property to display the Points.
        public ObservableCollection<Point> PointsList
        {
            get
            {
                return _pointsList;
            }

            set
            {
                if (_pointsList != value)
                    _pointsList = value;
            }
        }

        // Determines if we are using 2D or 3D Graphing.
        public GraphType GraphTypeCheck
        {
            get
            {
                return _type;
            }
            set
            {
                if (_type != value)
                    _type = value;

                base.OnPropertyChanged("GraphTypeCheck");
            }
        }

        // X Values from Edit Field.
        public String x
        {
            get
            {
                return _x;
            }

            set
            {
                if (_x != value)
                {
                    _x = value;
                }

                base.OnPropertyChanged("_x");
            }
        }

        // Y Values from Edit Field.
        public String y
        {
            get
            {
                return _y;
            }

            set
            {
                if (_y != value)
                {
                    _y = value;
                }

                base.OnPropertyChanged("_y");
            }
        }

        // Z Values from Edit Field.
        public String z
        {
            get
            {
                return _z;
            }

            set
            {
                if (_z != value)
                {
                    _z = value;
                }

                base.OnPropertyChanged("_z");
            }
        }

        #endregion // Properties.

        #region Commands

        // Command to Add a Point to the Collection.
        public ICommand AddPointCommand
        {
            get
            {
                if (_addPointCommand == null)
                {
                    _addPointCommand = new RelayCommand(param => this.AddPoint(), param => this.CanAddPoint());
                }
                return _addPointCommand;
            }
        }

        public ICommand EditPointCommand
        {
            get
            {
                if(_editPointCommand == null)
                    _editPointCommand = new RelayCommand(param => this.EditPoint(), param => this.CanEditPoint());
                return _editPointCommand;
            }
        }

        // Command to Graph the Formula from _expression.
        public ICommand GraphFormulaCommand
        {
            get
            {
                if (_graphCommand == null)
                {
                    _graphCommand = new RelayCommand(param => this.Graph(), param => this.IsExpressionValid());
                }
                return _graphCommand;
            }
        }

        #endregion // Commands.

        #region AddPoint

        // Used to satisfy relay command parameters.
        private bool CanAddPoint()
        {
            return true;
        }

        // Called when Add Point Button Pressed.
        private void AddPoint()
        {
            Point newPoint = new Point();
            newPoint.x = Double.Parse(_x);
            newPoint.y = Double.Parse(_y);
            if (!string.IsNullOrEmpty(_z))
                newPoint.z = Double.Parse(_z);

            PointsList.Add(newPoint);
            base.OnPropertyChanged("PointsList");
        }

        #endregion // AddPoint.

        #region EditPoint

        private bool CanEditPoint()
        {
            return true;
        }

        // Called when Edit Point Button Pressed.
        private void EditPoint()
        {
            _openEditWindow.OpenView("EditPointsView");
        }

        #endregion // EditPoint.

        #region GraphFormula

        // Used to satisfy relay command parameters.
        private bool IsExpressionValid()
        {
            return true;
        }

        // Called when Add Point Button Pressed.
        private void Graph()
        {
            // Still needs to be implemented.
        }

        #endregion // GraphFormula.

        #region Validation Checks
        //Error message for IDATAERROR
        public string Error
        {
            get
            {
                return this[string.Empty];
            }
        }

        //Property verification for IDATAERROR
        public string this[string propertyName]
        {
            get
            {
                string result = null;
                propertyName = propertyName ?? string.Empty;
                double Num;
                bool xIsNum = double.TryParse(this.x, out Num);
                bool yIsNum = double.TryParse(this.y, out Num);
                bool zIsNum = double.TryParse(this.z, out Num);
                isValid = true;
                base.OnPropertyChanged("isValid");
                
                if (propertyName == string.Empty || propertyName == "x" || propertyName == "y" || propertyName == "z")
                {
                    if (string.IsNullOrEmpty(this.x) || string.IsNullOrEmpty(this.y))
                    {
                        result = "Value cannot be blank";
                        isValid = false;
                        base.OnPropertyChanged("isValid");
                    }
                    else if (!xIsNum || !yIsNum || !zIsNum)
                    {
                        result = "Value need to be a number";
                        isValid = false;
                       base.OnPropertyChanged("isValid");
                    }

                }
                return result;

            }
        }

        //To determine if button should be enabled or not
        public bool isValid { get; set; }
        #endregion//Validation Checks
    }
}
